package com.zzyl.nursing.service.impl;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.utils.DateUtils;
import com.zzyl.nursing.domain.Device;
import com.zzyl.nursing.job.vo.IotMsgService;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.util.DateTimeZoneConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.DeviceDataMapper;
import com.zzyl.nursing.domain.DeviceData;
import com.zzyl.nursing.service.IDeviceDataService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import java.util.Arrays;
import java.util.Map;

/**
 * 设备数据Service业务层处理
 * 
 * @author Nan
 * @date 2025-06-02
 */
@Service
public class DeviceDataServiceImpl extends ServiceImpl<DeviceDataMapper,DeviceData> implements IDeviceDataService
{
    @Autowired
    private DeviceDataMapper deviceDataMapper;

    // 注入根据id 查询设备数据的bean
    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    /**
     * 查询设备数据
     * 
     * @param id 设备数据主键
     * @return 设备数据
     */
    @Override
    public DeviceData selectDeviceDataById(Long id)
    {
        return getById(id);
    }

    /**
     * 查询设备数据列表
     * 
     * @param deviceData 设备数据
     * @return 设备数据
     */
    @Override
    public List<DeviceData> selectDeviceDataList(DeviceData deviceData)
    {
        return deviceDataMapper.selectDeviceDataList(deviceData);
    }

    /**
     * 新增设备数据
     * 
     * @param deviceData 设备数据
     * @return 结果
     */
    @Override
    public int insertDeviceData(DeviceData deviceData)
    {
        return save(deviceData)?1:0;
    }

    /**
     * 修改设备数据
     * 
     * @param deviceData 设备数据
     * @return 结果
     */
    @Override
    public int updateDeviceData(DeviceData deviceData)
    {
        return updateById(deviceData)?1:0;
    }

    /**
     * 批量删除设备数据
     * 
     * @param ids 需要删除的设备数据主键
     * @return 结果
     */
    @Override
    public int deleteDeviceDataByIds(Long[] ids)
    {
        return removeByIds(Arrays.asList(ids))?1:0;
    }

    /**
     * 删除设备数据信息
     * 
     * @param id 设备数据主键
     * @return 结果
     */
    @Override
    public int deleteDeviceDataById(Long id)
    {
        return removeById(id)?1:0;
    }

    // 把数据注入到我们自己表中
    @Override
    public void batchInsertFromContentStr(String contentStr) {
      /*  我们要把数据存到哪里？
        1. 存到我们自己库中的 对应的设备数据表中：
            所有我们要先 判断 我们自己库中 存不存在 这个设备，不存在 直接return 
        2. 如果我们表中 存在这个设备：
            1. 把消息队列 给我们返回的数据，构建成 我们表中 需要的数据
            2， 把构建的数据 添加到数据库中
      * */
        
    //     为了方便操作，先把消息队列给我们的 字符串内容转为 对象
        JSONObject jsonObject = JSONUtil.parseObj(contentStr);

    //  从 json 对象中取出我们需要的某个属性
        String deviceId = jsonObject.getByPath("notify_data.header.device_id",String.class);

    //     判断设备id 是否为空，不为空 我们才操作
        if(StrUtil.isEmpty(deviceId)){
            return ;
        }
    //     此时说明 有设备 id，从表中查询该设备id 的数据
        LambdaQueryWrapper<Device>   queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.eq(Device::getIotId,deviceId);

        Device device = deviceMapper.selectOne(queryWrapper);

    //     判断查到的 设备数据 为不为 null ;

        if(JSONUtil.isNull(device)){
            return ;
        }
    //     此时说明我们查到的数据 不为null ,即表中 存在我们的设备

    //     因为 我们的数据表 中的数据 包含我们的设备表中的一些数据，所有要取到里面的一些信息
    //     我们数据表中的 一条信息就是1条设备表中的数据+ iot 给我们分发的数据

    //     1. 先获取 json 对象中 我们需要的 设备数据

        IotMsgService iotMsgService = jsonObject.getByPath("notify_data.body.services[0]", IotMsgService.class);

    //     从我们定义的vo 中 获取数据
    // 服务id
        String serviceId = iotMsgService.getServiceId();
        // 激活时间
        String eventTimeStr = iotMsgService.getEventTime();
        // 每一个设备中 所拥有的属性，1个属性 在我们数据表中 就是1条数据
        Map<String, Object> properties = iotMsgService.getProperties();

    //     2. 修改时间格式 我们页面需要的时间：1.先把字符串时间，转为我们的国际时间，2，把国际时间转为我们国内的时间

        LocalDateTime eventTimeUTC = LocalDateTimeUtil.parse(eventTimeStr, "yyyyMMdd'T'HHmmss'Z'");
    //     把国际时间 转为 我们需要的国内时间
        LocalDateTime  eventTime = DateTimeZoneConverter.utcToShanghai(eventTimeUTC);

    //     3,循环遍历 我们的属性，每遍历1次，都要向表中 添加1条数据，但是我们不能 每循环1次 就向表中 添加1个数据，
        //     所以我们定义1个集合，我们统一把集合添加到表中

        List<DeviceData> list = new ArrayList<>();
        properties.forEach((key,value)->{
        // key 对应我们数据表中的function_id
        //     value 对应 我们数据表的 data_value
        //     激活时间 对应我们表中的 alarm_time
        //     除此之外我们还要把设备表中的数据 存到我们数据表中
            DeviceData deviceData = BeanUtil.toBean(device, DeviceData.class);
            deviceData.setId(null);
            // 存key
            deviceData.setFunctionId(key);
            // 存value
            deviceData.setDataValue(value.toString());
            // 存时间
            deviceData.setAlarmTime(eventTime);
        //     添加到list 集合中
            list.add(deviceData);
        });

    //     批量保存
    //     这里我们要用 try catch 的 原因是 如果我们不应trt catch 那么当添加失败的时候，我们控制台 不会提示
    //     加上try catch方便我们捕获异常,并打印出来

        // 此时还有1个 报错就是 我们mybatis-plus中 有个字段填充，我们调用的saveBatch方法是 mybatis-plus提供的，所以在自动填充处
        // 识别到我们当前的 请求 不是 小程序，因为我们在自动填充的地方 判断了是不是小程序的，在判断小程序的地方，判断不是 小程序的
        // 就 return true 然后true 就会自动填充，但是自动填充的是 基于http 协议的，我们 当前的消息注入是  AMQP协议 ，所以报错，所以我们还要更改 mybatis-plus 自动填充的代码
        //  用 try catch 包裹下我们 判断小程序的地方，进入catch 就return false ,不让他自动填充

        try {
            this.saveBatch(list);

        //     每保存1次 就向redis 中 存1次，涉及到一样的就 覆盖

            redisTemplate.boundHashOps(CacheConstants.IOT_DEVICE_LAST_DATA).put(deviceId,JSONUtil.toJsonStr(list));

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}
